package parasoft.centrap.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Klasa dostarcza mapy w�a�ciwo�ci.<br>
 * Opcjonalnie dzia�anie wed�ug wzorca obserwatora.<br>
 * Rozszerza obiekt o dodatkowe w�a�ciwo�ci, kt�re mog� by� u�ywane zamiast dodawania nowych metod
 * @since centrala-2_38
 */
public class Container{
    /** Mapa do dodatkowych w�a�ciwo�ci kontenera
     * @since centrala-2_38 */
	private Map<String,Object> values  = new HashMap<String,Object>();
    /** Mapa do nas�uchu dla operacji dodawanie, modyfikacji, czytania i usuwania obiektu
     * @since centrala-2_38 */
	private final Map<String, ContainerListener<?>> listeners  = new HashMap<String, ContainerListener<?>>();
	/** Mapa do nas�uchu dla operacji dodawanie, modyfikacji, czytania i usuwania obiektu konkretnej klasy
     * @since centrala-2_38 */
	private final Map<Class<?>, ContainerListener<?>> classlisteners  = new HashMap<Class<?>, ContainerListener<?>>();
	/** Lista do dodatkowych w�a�ciwo�ci kontenera
	 * @since centrala-2_44 */
	private List<Object> list = new ArrayList<Object>();
	/**
	 * Konstruktor domy�lny
	 */
	public Container(){}
	/**
	 * Konstruktor kopiuj�cy
	 */
	public Container(final Container c){
		this(c.get());
		for(final Object value : c.getList()){
			list.add(value);
		}
		
	}
	/**
	 * Konstruktor kopiuj�cy
	 */
	public Container(final Map<String, Object> map){
		for(final Map.Entry<String, Object> entry : map.entrySet()){
			values.put(entry.getKey(), entry.getValue());
		}
	}
	
	/**
	 * Tworzy nowy kontener
	 * @return new this
	 * @since centrala-2_44
	 */
	public static Container create(){
		return new Container();
	}
	/**
	 * Konstruktor dodaj�cy mo�liwo�� ustawienie nas�uchu dla wszystkich obiekt�w tego kontenera
	 * @param cl
	 */
	public Container(final ContainerListener<Object> cl){
		addListener(cl);
	}
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu char
     * @param key klucz
     * @param v warto�� char
     * @return this
     * @since centrala-2_38
     */
    public Container set(final String key, final char v){
    	setString(key, String.valueOf(v));return this;
    }
    public Container set(final Enum<?> key, final char v){
    	return set(key.toString(), v);
    }
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu String::object.toString.<br>
     * W przypadku kiedy obiekt wskazuje na null, zostaje dodany napis "null"
     * @param key klucz
     * @param v obiekt
     * @return this
     * @since centrala-2_38
     */
    public <T>Container setString(final String key, final T v){
    	p(key, String.valueOf(v));
    	return this;
    }
    public <T>Container setString(final Enum<?> key, final T v){
    	return setString(key.toString(), v);
    }
    
    /**
     * Ustawia dodatkow� w�a�ciwo�� dowolnego typu
     * @param key klucz
     * @param v warto�� object
     * @return this
     * @since centrala-2_38
     */
    public <T>Container set(final String key, final T v){
    	if(v instanceof String){
    		p(key, (String)v);
		}else{
			p(key, v);
		}
    	return this;
    }
    public <T>Container set(final Enum<?> key, final T v){
    	return set(key.toString(), v);
    }
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu List
     * @param key klucz
     * @param v warto�� object
     * @return this
     * @since centrala-2_43
     */
    @SuppressWarnings("unchecked")
	public <T>Container addToList(final String key,final T v){
		List<T> pre = getList(key);
		if(pre == null){
			pre = new ArrayList<T>();
		}
		if(v instanceof List<?>){
			pre.addAll((List<T>)v);
		}else{
			pre.add(v);
		}
    	p(key, pre);
    	return this;
    }
	public <T>Container addToList(final Enum<?> key,final T v){
		return addToList(key.toString(), v);
    }
     /**
     * Ustawia dodatkow� w�a�ciwo�� typu List
     * @param key klucz
     * @param v warto�� object
     * @return this
     * @since centrala-2_43
     */
    public Container addToList(final String key,final String v){
		List<String> pre = getList(key);
		if(pre == null){
			pre = new ArrayList<String>();
		}
		pre.addAll(StringUtil.getList(v));
    	p(key, pre);
    	return this;
    }
    public Container addToList(final Enum<?> key,final String v){
		return addToList(key.toString(), v);
    }
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu boolean
     * @param key klucz
     * @param v warto�� boolean
     * @return this
     * @since centrala-2_38
     */
    public Container set(final String key, final boolean v){
    	p(key, Boolean.valueOf(v));return this;
    }
    public Container set(final Enum<?> key, final boolean v){
    	return set(key.toString(), v);
    }
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu int
     * @param key klucz
     * @param v warto�� int
     * @return this
     * @since centrala-2_38
     */
    public Container set(final String key, final int v){
    	p(key, new Integer(v));return this;
    }
    public Container set(final Enum<?> key, final int v){
    	return set(key.toString(), v);
    }
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu long
     * @param key klucz
     * @param v warto�� long
     * @return this
     * @since centrala-2_38
     */
    public Container set(final String key, final long v){
    	p(key, new Long(v));return this;
    }
    public Container set(final Enum<?> key, final long v){
    	return set(key.toString(), v);
    }
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu float
     * @param key klucz
     * @param v warto�� float
     * @return this
     * @since centrala-2_38
     */
    public Container set(final String key, final float v){
    	p(key, new Float(v));return this;
    }
    public Container set(final Enum<?> key, final float v){
    	return set(key.toString(), v);
    }
    /**
     * Ustawia dodatkow� w�a�ciwo�� typu double
     * @param key klucz
     * @param v warto�� double
     * @return this
     * @since centrala-2_38
     */
    public Container set(final String key, final double v){
    	p(key, new Double(v));return this;
    }
    public Container set(final Enum<?> key, final double v){
    	return set(key.toString(), v);
    }    
	/**
	 * Czy obiekt zawiera dodatkow� w�a�ciwo�ci typu boolean o nazwie key z warto�ci� true
	 * @param key klucz
	 * @return get(key)==true
	 * @since centrala-2_38
	 */
	public boolean is(final String key){
		return is(key, false);
	}
	public boolean is(final Enum<?> key){
		return is(key.toString(), false);
	}
	/**
	 * Czy obiekt zawiera dodatkow� w�a�ciwo�ci typu boolean o nazwie key z warto�ci� true.<br>
	 * W przeciwnym razie zwraca warto�� domy�ln� def.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i por�wnywana do true
	 * @param key klucz
	 * @param def warto�� domy�lna
	 * @return get(key)==true
	 * @since centrala-2_38
	 */
	public boolean is(final String key,final boolean def){
		final Object o = get(key);
		if(o instanceof Boolean){
			return ((Boolean)o).booleanValue();
		}
		if(o instanceof String){
			final String s = (String)o;
			return ((s.trim().length()>0) && s.toLowerCase().equals("true"));
		}
		return def;
	}
	public boolean is(final Enum<?> key,final boolean def){
		return is(key.toString(), def);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu String lub reprezentacj� metody object.toString() lub null je�eli nie mamy dodatkowej w�a�ciwo�ci 
	 * @param k klucz
	 * @return get(k)::String
	 * @since centrala-2_38
	 */
	public String getString(final String k){
		return getString(k, null);
	}
	public String getString(final Enum<?> k){
		return getString(k.toString(), null);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu String lub reprezentacj� metody object.toString() lub null je�eli nie mamy dodatkowej w�a�ciwo�ci
	 * @param k klucz
	 * @return get(k)::String
	 * @since centrala-2_38
	 */
	public String getString(final String k, final String def){
		final Object o = get(k);
		if(o!=null){
			if(o instanceof String){
				return (String)o;
			}
			return o.toString();
		}
		return def;
	}
	public String getString(final Enum<?> k, final String def){
		return getString(k.toString(), def);
	}

	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu int.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ int.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca 0
	 * @param k klucz
	 * @return get(k)::int
	 * @since centrala-2_38
	 */
	public int getInt(final String k){
		return getInt(k, 0);
	}
	public int getInt(final Enum<?> k){
		return getInt(k.toString(), 0);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu int.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ int.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca def
	 * @param k klucz
	 * @param def warto�� domy�lna
	 * @return get(k)::String
	 * @since centrala-2_38
	 */
	public int getInt(final String k, final int def){
		final Object o = get(k);
		if(o instanceof Integer){
			return ((Integer)o).intValue();
		}
		if(o!=null){
			final String s = o.toString();
			if(s.trim().length()>0){
				try {
					return Integer.parseInt(s);
				} catch (final NumberFormatException e) {
					return def;
				}
			}
		}
		return def;
	}
	public int getInt(final Enum<?> k, final int def){
		return getInt(k.toString(), def);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu long.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ long.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca 0
	 * @param k klucz
	 * @return get(k)::long
	 * @since centrala-2_38
	 */
	public long getLong(final String k){
		return getLong(k, 0);
	}
	public long getLong(final Enum<?> k){
		return getLong(k.toString(), 0);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu long.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ long.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca def
	 * @param k klucz
	 * @param def warto�� domy�lna
	 * @return get(k)::long
	 * @since centrala-2_38
	 */
	public long getLong(final String k, final long def){
		final Object o = get(k);
		if(o instanceof Long){
			return ((Long)o).longValue();
		}
		if(o!=null){
			final String s = o.toString();
			if(s.trim().length()>0){
				try {
					return Long.parseLong(s);
				} catch (final NumberFormatException e) {
					return def;
				}
			}
		}
		return def;
	}
	public long getLong(final Enum<?> k, final long def){
		return getLong(k.toString(), def);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu float.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ float.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca 0
	 * @param k klucz
	 * @return get(k)::float
	 * @since centrala-2_38
	 */
	public float getFloat(final String k){
		return getFloat(k, 0);
	}
	public float getFloat(final Enum<?> k){
		return getFloat(k.toString(), 0);
	}

	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu float.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ float.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca def
	 * @param k klucz
	 * @param def warto�� domy�lna
	 * @return get(k)::float
	 * @since centrala-2_38
	 */
	public float getFloat(final String k, final float def){
		final Object o = get(k);
		if(o instanceof Float){
			return ((Float)o).floatValue();
		}
		if(o!=null){
			final String s = o.toString();
			if(s.trim().length()>0){
				try {
					return Float.parseFloat(s);
				} catch (final NumberFormatException e) {
					return def;
				}
			}
		}
		return def;
	}
	public float getFloat(final Enum<?> k, final float def){
		return getFloat(k.toString(), def);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu double.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ double.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca 0
	 * @param k klucz
	 * @return get(k)::double
	 * @since centrala-2_38
	 */
	public double getDouble(final String k){
		return getDouble(k, 0);
	}
	public double getDouble(final Enum<?> k){
		return getDouble(k.toString(), 0);
	}

	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu Double.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest wyci�gana reprezentacja ci�gu znakowego i parsowana na typ double.<br>
	 * W przypadku b��du parsowania lub warto�ci null zwraca def
	 * @param k klucz
	 * @param def warto�� domy�lna
	 * @return get(k)::double
	 * @since centrala-2_38
	 */
	public double getDouble(final String k, final double def){
		final Object o = get(k);
		if(o instanceof Double){
			return ((Double)o).doubleValue();
		}
		if(o!=null){
			final String s = o.toString();
			if(s.trim().length()>0){
				try {
					return Double.parseDouble(s);
				} catch (final NumberFormatException e) {
					return def;
				}
			}
		}
		return def;
	}
	public double getDouble(final Enum<?> k, final double def){
		return getDouble(k.toString(), def);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu List.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest tworzona nowa lista.<br>
	 * @param k klucz
	 * @return get(k)::List
	 * @since centrala-2_43
	 */
	public <T>List<T> getList(final String k){
		return getList(k, new ArrayList<T>());
	}
	public <T>List<T> getList(final Enum<?> k){
		return getList(k.toString(), new ArrayList<T>());
	}

	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu List.<br>
	 * W przypadku je�eli w�a�ciwo�� jest typu String jest tworzona nowa lista.<br>
	 * W przypadku warto�ci null zwraca def
	 * @param k klucz
	 * @param def warto�� domy�lna
	 * @return get(k)::List
	 * @since centrala-2_43
	 */
	@SuppressWarnings("unchecked")
	public <T>List<T> getList(final String k, final List<T> def){
		final Object o = get(k);
		try{
			if(o instanceof List<?>){
				return ClassUtil.toValue(o);
			}
			if(o!=null){
				return new ArrayList<T>() {
					/** Container.java */
					private static final long serialVersionUID = 8354428398700162113L;

					{
						add((T) o);
					}
				};
			}
		}catch(final Exception e){}
		return def;
	}
	public <T>List<T> getList(final Enum<?> k, final List<T> def){
		return getList(k.toString(), def);
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu Object lub null je�eli nie mamy dodatkowej w�a�ciwo�ci
	 * @param k klucz
	 * @return get(key)::Object
	 * @since centrala-2_38
	 */
	@SuppressWarnings("unchecked")
	public <T>T get(final String k){
		return (T)(get(k, null));
	}
	@SuppressWarnings("unchecked")
	public <T>T get(final Enum<?> k){
		return (T)(get(k.toString(), null));
	}

	/**
	 * Dodaje nas�uch dla operacji wykonywanych na wszystkich obiektach w kontenerze
	 * @param <T>
	 * @return this
	 * @since centrala-2_38
	 */
	public Container addListener(final ContainerListener<Object> cl){
		classlisteners.put(Object.class, cl.set(this));
		return this;
	}
	/**
	 * Dodaje nas�uch dla operacji wykonywanych na obiekcie
	 * @param key klucz obiektu
	 * @param cl obiekt nas�uchu
	 * @return this
	 * @since centrala-2_38
	 */
	public <T>Container addListener(final Class<T> key, final ContainerListener<T> cl){
		classlisteners.put(key,  cl.set(this));
		return this;
	}
	/**
	 * Dodaje nas�uch dla operacji wykonywanych na obiekcie
	 * @param key klucz obiektu
	 * @param cl obiekt nas�uchu
	 * @return this
	 * @since centrala-2_38
	 */
	public <T>Container addListener(final String key, final ContainerListener<T> cl){
		listeners.put(key, cl.set(this));
		return this;
	}
	public <T>Container addListener(final Enum<?> key, final ContainerListener<T> cl){
		return addListener(key.toString(), cl);
	}
	/**
	 * Usuwa nas�uch na�o�ony na kontene dla wszystkich jego obiekt�w
	 * @return this
	 * @since centrala-2_44
	 */
	public Container removeListener(){
		return removeListener(Object.class);
	}
	/**
	 * Usuwa nas�uch na�o�ony na obiekty podanej klasy
	 * @param key klucz obiektu
	 * @return this
	 * @since centrala-2_44
	 */
	public Container removeListener(final Class<?> key){
		classlisteners.remove(key);
		return this;
	}
	/**
	 * Sprawdza czy kontener ma aktywny nas�uch dla wszystkich jego element�w
	 * @return ma nas�uch
	 * @since centrala-2_44
	 */
	public boolean hasListener(){
		return hasListener(Object.class);
	}
	/**
	 * Sprawdza czy kontener ma aktywny nas�uch na obiektach podanej klasy
	 * @param key klucz obiektu
	 * @return ma nas�uch
	 * @since centrala-2_44
	 */
	public boolean hasListener(final Class<?> key){
		return classlisteners.containsKey(key);
	}
	/**
	 * Usuwa nas�uch na�o�ony na obiekcie
	 * @param key klucz obiektu
	 * @return this
	 * @since centrala-2_38
	 */
	public Container removeListener(final String key){
		listeners.remove(key);
		return this;
	}
	public Container removeListener(final Enum<?> key){
		return removeListener(key.toString());
	}
	/**
	 * Sprawdza czy kontener ma aktywny nas�uch na obiekcie
	 * @param key klucz obiektu
	 * @return ma nas�uch
	 * @since centrala-2_38
	 */
	public boolean hasListener(final String key){
		return listeners.get(key)!=null;
	}
	public boolean hasListener(final Enum<?> key){
		return listeners.get(key.toString())!=null;
	}
	/**
	 * Ustawia dodatkow� w�a�ciwo�� dowolnego typu
	 * @param k klucz
	 * @param v warto�� Object
	 * @return this
	 * @since centrala-2_38
	 */
	@SuppressWarnings("unchecked")
	private <T>Container p(final String k, final T v){
		if(k!=null){
			T toInsert = v;
			if((classlisteners!=null) && (classlisteners.size()>0)){
				final boolean has = has(k);
				final T vg = (T) values.get(k);
				final List<Class<T>> vclasses = ClassUtil.getClasses(v);
				for(final Class<T> c : vclasses){
					if(classlisteners.containsKey(c)){
						if(has){
							toInsert= getContainerListener(classlisteners, c).onUpdate(vg, v);
						}else{
							toInsert= getContainerListener(classlisteners, c).onInsert(v);
						}
					}
				}
	    	}
			if((listeners.size()>0) && listeners.containsKey(k)){
				if(has(k)){
					final T vg = (T)(values.get(k));
					toInsert= getContainerListener( listeners.get(k), vg).onUpdate(vg, v);
				}else{
					toInsert= getContainerListener( listeners.get(k), v).onInsert(v);
				}
			}
			values.put(k, toInsert);
		}
		return this;
	}
	/**
	 * Pobiera dodatkow� w�a�ciwo�� typu Object lub null je�eli nie mamy dodatkowej w�a�ciwo�ci
	 * @param k klucz
	 * @return get(key)::Object
	 * @since centrala-2_38
	 */
	@SuppressWarnings("unchecked")
	public <T>T get(final String k, final T def){
		T out = def;
		if(has(k)){
	    	out = (T)values.get(k);
	    	if(out==null){
	    		out=def;
	    	}
		}
		if((classlisteners!=null) && (classlisteners.size()>0)){
			final boolean has = has(k);
			final List<Class<T>> vclasses = ClassUtil.getClasses(out);
			for(final Class<T> c : vclasses){
				if(classlisteners.containsKey(c)){
					if(has){
						out= getContainerListener(classlisteners, c).onRead(out);
					}else{
						out= getContainerListener(classlisteners, c).onRead(out, def);
					}
				}
			}
    	}
		if((listeners.size()>0) && listeners.containsKey(k)){
			if(def==null){
				out=getContainerListener(listeners.get(k), out).onRead(out);
			}else{
				out=getContainerListener(listeners.get(k), out).onRead(out, def);
			}
		}
		return out;
	}
	public <T>T get(final Enum<?> k, final T def){
		return get(k.toString(), def);
	}
	
	/**
	 * Usuwa obiekt z kontenera
	 * @param key klucz obiektu
	 * @return this
	 * @since centrala-2_38
	 */
	public Container remove(final String key){
		boolean toDelete = has(key); 
		if((classlisteners!=null) && (classlisteners.size()>0)){
			final List<Class<Object>> vclasses = ClassUtil.getClasses(values.get(key));
			for(final Class<Object> c : vclasses){
				if(classlisteners.containsKey(c)){
					toDelete= getContainerListener(classlisteners, c).onDelete(toDelete);
				}
			}
    	}
		if((listeners.size()>0) && listeners.containsKey(key)){
			toDelete = listeners.get(key).onDelete(toDelete);
		}
		if(toDelete){
			values.remove(key);
		}
		return this;
	}
	public Container remove(final Enum<?> key){
		return remove(key.toString());
	}
	/**
	 * Sprawdza czy obiekt zawiera podan� dodatkow� w�a�ciwo��
	 * @param key klucz
	 * @return czy zawiera w�a�ciwo��
	 * @since centrala-2_38
	 */
	public <T>boolean has(final String key){
		boolean out = (key!=null) && values.containsKey(key);
		if((classlisteners!=null) && (classlisteners.size()>0)){
			final List<Class<Object>> vclasses = ClassUtil.getClasses(values.get(key));
			for(final Class<Object> c : vclasses){
				if(classlisteners.containsKey(c)){
					out= getContainerListener(classlisteners, c).onCheck(out);
				}
			}
    	}
		if((listeners.size()>0) && listeners.containsKey(key)){
			out=getContainerListener(listeners.get(key), ClassUtil.toValue(values.get(key))).onCheck(out);
		}
		return  out;
	}
	public <T>boolean has(final Enum<?> key){
		return has(key.toString());
	}
	/**
	 * @param <T>
	 * @param cl
	 * @param key
	 * @return
	 * @since centrala-2_43
	 */
	private <T>ContainerListener<T> getContainerListener(final ContainerListener<?> cl, final T key){
		if((cl!=null) && ClassUtil.equalsClass(ClassUtil.getParameterizedType(cl) , ClassUtil.getClass(key) )){
			return ClassUtil.toValue(cl);
		}
		return new ContainerListenerAdapter<T>();
	}
	/**
	 * @param <T>
	 * @param m
	 * @param vclass
	 * @return
	 * @since centrala-2_43
	 */
	private <T>ContainerListener<T> getContainerListener(final Map<Class<?>, ContainerListener<?>> m, final Class<T> vclass){
		final ContainerListener<?> cl = m.get(vclass);
		if((cl!=null) && ClassUtil.equalsClass(ClassUtil.getParameterizedType(cl) , vclass )){
			return ClassUtil.toValue(cl);
		}
		return new ContainerListenerAdapter<T>();
	}
	/**
	 * Zwraca map� dodatkowych w�a�ciwo�ci obiektu(nigdy null)
	 * @return mapa
	 * @since centrala-2_38
	 */
	public Map<String, Object> get(){
		return new HashMap<String, Object>(values);
	}
	/**
	 * @param c nowy typ mapy: HashMap,Hashtable,LinkedHashMap etc.
	 * @return this
	 * @since centrala-2_44
	 */
	@SuppressWarnings("unchecked")
	public Container setMapType(final Class<?> c){
		if(c!=null){
			try {
				Map<String, Object> tmp = null;
				if(values.size()>0){
					tmp = get();
				}
				values = (Map<String, Object>) c.newInstance();
				if(tmp!=null){
					values.putAll(tmp);
				}
			} catch (final InstantiationException e) {
				e.printStackTrace();
			} catch (final IllegalAccessException e) {
				e.printStackTrace();
			} catch(final ClassCastException cce){
				cce.printStackTrace();
			}
		}
		return this;
	}
	/**
	 * Ustawia typ listy
	 * @param c nowy typ listy: ArrayList,Vector,LinkedList etc.
	 * @return this
	 * @since centrala-2_44
	 */
	@SuppressWarnings("unchecked")
	public Container setListType(final Class<?> c){
		if(c!=null){
			try {
				List<Object> tmp = null;
				if(list.size()>0){
					tmp = getList();
				}
				list = (List<Object>) c.newInstance();
				if(tmp!=null){
					list.addAll(tmp);
				}
			} catch (final InstantiationException e) {
				e.printStackTrace();
			} catch (final IllegalAccessException e) {
				e.printStackTrace();
			} catch(final ClassCastException cce){
				cce.printStackTrace();
			}
		}
		return this;
	}
	/**
	 * Pobiera kopi� listy
	 * @return List
	 * @since centrala-2_44
	 */
	public List<Object> getList(){
		return new ArrayList<Object>(list);
	}
	/**
	 * Sprawdza czy kontener zawiera dodatkow� w�a�ciwo�� w zadanym indeksi
	 * @param idx numer rekordu w li�cie
	 * @return boolean
	 * @since centrala-2_44
	 */
	public boolean has(final int idx){
		boolean out = ((idx >= 0) && (idx < list.size()))&& (list.get(idx)!=null);
		Object ob = null;
		if(out){
			ob = list.get(idx);
		}
		if((classlisteners!=null) && (classlisteners.size()>0)){
			final List<Class<Object>> vclasses = ClassUtil.getClasses(ob);
			for(final Class<Object> c : vclasses){
				if(classlisteners.containsKey(c)){
					out= getContainerListener(classlisteners, c).onCheck(out);
				}
			}
    	}
		return out;
	}
	/**
	 * Dodaje dodatkow� w�a�ciwo�� dowolnego typu w li�cie
	 * @param o obiekt dodania
	 * @return ten obiekt
	 * @since centrala-2_44
	 */
	public Container put(final Object o){
		return set(list.indexOf(o), o);
	}
	/**
	 * Ustawia dodatkow� w�a�ciwo�� dowolnego typu w li�cie
	 * @param o obiekt dodania
	 * @return ten obiekt
	 * @since centrala-2_44
	 */
	public Container set(final int idx , final Object o){
		Object toInsert = o;
		final boolean has = has(idx);
		if (classlisteners != null) {
			final Class<Object> vclass = ClassUtil.getClass(o);
			if (vclass != null) {
				if (classlisteners.size() > 0) {
					Object vg = null;
					if(has){
						vg = (list.get(idx));
					}
					final List<Class<Object>> vclasses = ClassUtil.getClasses(o);
					for(final Class<Object> c : vclasses){
						if(classlisteners.containsKey(c)){
							if (has) {
								toInsert = getContainerListener(classlisteners,	c).onUpdate(vg, o);
							} else {
								toInsert = getContainerListener(classlisteners,	c).onInsert(o);
							}
						}
					}
				}
			}
		}
		if (has) {
			list.add(idx, toInsert);
		}else{
			list.add(toInsert);
		}
		return this;
	}
	/**
	 * Pobiera element z listy o indeksie idx
	 * @param idx numer elementu
	 * @return Object
	 * @since centrala-2_44
	 */
	public Object get(final int idx){
		Object out = null;
		final boolean has = has(idx);
		if(has){
	    	out = list.get(idx);
		}
		if((classlisteners!=null) && (classlisteners.size()>0)){
			final List<Class<Object>> vclasses = ClassUtil.getClasses(out);
			for(final Class<Object> c : vclasses){
				if(classlisteners.containsKey(c)){
					if(has){
						out= getContainerListener(classlisteners, c).onRead(out);
					}else{
						out= getContainerListener(classlisteners, c).onRead(out, null);
					}
				}
			}
    	}
		return list.get(idx);
	}
	/**
	 * Usuwa obiekt z listy w kontenerze
	 * @param idx numer elementu
	 * @return this
	 * @since centrala-2_44
	 */
	public Container remove(final int idx){
		final boolean has = has(idx);
		boolean toDelete = has; 
		if((classlisteners!=null) && (classlisteners.size()>0)){
			final List<Class<Object>> vclasses = ClassUtil.getClasses(list.get(idx));
			for(final Class<Object> c : vclasses){
				if(classlisteners.containsKey(c)){
					toDelete= getContainerListener(classlisteners, c).onDelete(toDelete);
				}
			}
    	}
		if(toDelete && has){
			list.remove(idx);
		}
		return this;
	}
}
